package genetic.q1;

import java.util.List;

import genetic.q1.Genotype;
import genetic.q1.Phenotype;
import genetic.q1.functions.ProgramObject;
import genetic.q1.functions.Operator;
import genetic.q1.functions.Statement;
import genetic.q1.functions.Variable;

public abstract class WithallPhenotype extends Phenotype{

	int length, min, max, blockSize, numBlocks;
	
	
	Statement[] statements;
	protected Variable[] readVars;
	protected Variable[] writeVars;
	Operator[] comparisons;
	protected Variable[] lSize;
	protected Variable returnVar;
	
	
	public WithallPhenotype(int numBlocks, int blockSize, int min, int max, Statement[] statements, Varpack varpack, Operator[] comparisons){
		this.numBlocks = numBlocks;
		this.blockSize = blockSize;
		this.length = numBlocks*blockSize;
		this.min = min;
		this.max = max;
		this.statements = statements;
		this.readVars = varpack.readVars;
		this.writeVars = varpack.writeVars;
		this.returnVar = varpack.returnVar;
		this.lSize = varpack.lsize;
		this.comparisons = comparisons;
	}
	
	@Override
	public Genotype createRandomInstance() {
		return new WithallGenotype(getRandomIntString(length, min, max));
	}

	@Override
	public Genotype[] crossover(Genotype g1, Genotype g2) {
		int[][] kids = crossover2(g1.getIntString(), g2.getIntString(), 1);
//		int[][] kids = crossover1(g1.getIntString(), g2.getIntString());
		return new Genotype[]{new WithallGenotype(kids[0]), new WithallGenotype(kids[1])};
	}

	@Override
	public List<Genotype> getInitialPopulation(int populationSize) {
//		List<Genotype> ans = new Vector<Genotype>();
//		for (int i = 0; i < populationSize; i++) {
//			int[] newArr = new int[length];
//			Arrays.fill(newArr, 7);
//			ans.add(new WithallGenotype(newArr));
//		}
//		return ans;
		return getInitialRandomPopulation(populationSize);
	}

	@Override
	public List<Genotype> getMatingPool(List<Genotype> population, int populationSize) {
		return getMatingPoolRouletteWheel(population, populationSize);
	}

	@Override
	public Genotype mutate(Genotype g, double Pm) {
		int[] tmp = mutation(g.getIntString(), Pm, min, max);
		return new WithallGenotype(tmp);
	}
	
	public Statement[] makeProgram(WithallGenotype g){
		Statement[] ans = new Statement[numBlocks];
		int[] intString = g.getIntString();
		for (int i=0; i<numBlocks; i++){
			Statement s = statements[intString[i*blockSize + 0] % statements.length ];
			ProgramObject[] evals = new ProgramObject[s.getNumVars()];
//			System.out.println(s);
			for (int j=0; j<evals.length; j++){
				evals[j] = s.choose(j, intString[i*blockSize + j+1], this);
//				System.out.println("\tevals["+j+"] = " + evals[j]);
			}
			ans[i] = s.CreateInstance(evals);
		}
		return ans;
	}
	
	public Variable getFromReadVars(int i){
		return readVars[i % readVars.length];
	}
	
	public Variable getFromReadWriteVars(int i){
		int tmp = i % (readVars.length + writeVars.length);
		if (tmp < readVars.length) return readVars[tmp];
		else return writeVars[tmp % writeVars.length];
	}
	
	public Variable getFromWriteVars(int i){
		return writeVars[i % writeVars.length];
	}
	
	public Operator getFromComparisons(int i){
		return comparisons[i % comparisons.length];
	}
	
	public Variable getFromLsizeVars(int i) {
		return lSize[i % lSize.length];
	}

}
